package ig.finanzas;

import ig.finanzas.riesgo.FactorRiesgoPersonal;
import ig.metrica.escenario.GeneraEscenarioBean;
import ig.util.excepciones.DatoInvalidoExcepcion;
import ig.util.excepciones.LogicaExcepcion;
import java.rmi.RemoteException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import javax.ejb.EJBException;
import javax.ejb.FinderException;
import javax.naming.NamingException;

/**
 *
 * Implementa los metodos y funciones de un contrato atomizable y que no representa titulo de propiedad.
 * @author  lfgarcia
 */
public class PosicionEspecieBean extends ContratoBean {    
    static final long serialVersionUID = 01;    
    /**
     *
     * Valor nominal de la posicion.
     *
     * @uml.property  name="valorNominal"
     *
     */
    
    private double valorNominal;    
    //private double valorCompra;
    
    /**
     *
     * Si el contrato es Disponible para la venta o negociable.
     *
     * @uml.property  name="tipo"
     *
     */
    
    private String tipo;    
    /**
     *
     * @uml.property  name="especiePK"
     *
     * @uml.associationEnd
     *
     */
    
    private EspeciePK especiePK;
    
    
    
    /**
     *
     * @return   Returns the valorNominal.
     *
     * @uml.property  name="valorNominal"
     *
     */
    
    public double getValorNominal(){        
        return valorNominal;
        
    }
    
    
    
        /*
         
        public double getValorCompra(){
         
                return valorCompra;
         
        }
         
         */
    
    
    
    /**
     *
     * Devuelve el tipo de contrato. Los valores validos son Disponible para la Venta y  negociables.
     *
     * @return
     *
     * @uml.property  name="tipo"
     *
     */
    
    public String getTipo(){
        
        return tipo;
        
    }
    
    
    
    /**
     *
     * @return   Returns the especiePK.
     *
     * @uml.property  name="especiePK"
     *
     */
    
    public EspeciePK getEspeciePK(){
        
        return especiePK;
        
    }
    
    
    
    /**
     *
     * @param tipo   The tipo to set.
     *
     * @uml.property  name="tipo"
     *
     */
    
    public void setTipo(String tipo) throws DatoInvalidoExcepcion, Exception{
        
        if (!tipo.equals(PosicionEspecie.TIPO_DISPONIBLEVENTA) && !tipo.equals(PosicionEspecie.TIPO_NEGOCIABLE)){
            
            throw new DatoInvalidoExcepcion("El tipo especificado para la posicion " + ((ContratoPK)ctx.getPrimaryKey()).toString() + " no es valido");
            
        }
        
        this.tipo = tipo;
        
    }
    
    
    
    /**
     *
     * Devuelve el precio limpio de la posicion a una fecha especifica.
     *
     * @param fecha
     *
     * @return
     *
     * @throws DatoInvalidoExcepcion Si la fecha es nula.
     *
     * @throws LogicaExcepcion Si no hay suficiente informacion para determinar el valor vigente.
     *
     */
    
    public double getPrecioLimpio(Date fecha) throws DatoInvalidoExcepcion, LogicaExcepcion{
        
        return valoresRegistrados.obtenerValorVigenteA(fecha, 0);
        
    }
    
    
    
    /**
     *
     * Valora el contrato a una fecha especifica.
     *
     * @param fecha
     *
     * @return
     *
     * @throws DatoInvalidoExcepcion Si la fecha especificada es nula.
     *
     * @throws LogicaExcepcion Si la entidad no posee valores historicos registrados,
     *
     * o si no se puede calcular el valor vigente de la tasa
     *
     * o si el valor calculado es imaginario.
     *
     * @throws FinderException Si no se puede encontrar la tasa de referencia del periodo
     *
     * especificado.
     *
     */
    
    public double valorar(Date fecha)
    
    throws DatoInvalidoExcepcion, LogicaExcepcion, FinderException{
        
        
        
        if (fecha == null)
            
            throw new DatoInvalidoExcepcion("La fecha especificada es nula.");
        
        
        
        if (valoresRegistrados == null)
            
            throw new LogicaExcepcion("La entidad no posee valores historicos registrados.");
        
        
        
        Date fechaultimopago = flujos.flujoAnteriorA(fecha).getFecha();
        
        TasaPago tasaPago = (TasaPago)tasasDePago.getRango(fecha);
        
        double i = tasaPago.tasaNominalPeriodo(fecha, fechaultimopago);
        
//		int numdiascorridos = (int)((fecha.getTime() - fechaultimopago.getTime())/(1000*60*60*24));
        int numdiascorridos = ManejadorFlujos.calcualarDias(fechaultimopago,fecha);
        
        
        //vpm = vnominal * preciolimpio + vnominal * i * diascorridos/365
        
        return valoresRegistrados.obtenerValorVigenteA(fecha, 0) +
                
                valorNominal * i * numdiascorridos / 365;
        
    }
    
    
    
    /**
     *
     * Calcula el cambio esperado de la serie de valores registrados del contrato.
     *
     * @param fecha
     *
     * @param definidor
     *
     * @return
     *
     * @throws DatoInvalidoExcepcion Si alguno de los parametros recibidos es invalido.
     *
     * @throws LogicaExcepcion Si la forma de calculo no permite obtener el valor, si no hay suficientes
     *
     * valores en la serie, si la informacion hallada no alcanza a ser una muestra estadisticamente representativa,
     *
     * o si la serie no permite el calculo utilizando diferencias logaritmicas.
     *
     */
    
    public double cambioEsperadoValoresRegistrados(Date fecha, DefinidorCalculoCambioEsperado definidor,boolean isPrecio) throws DatoInvalidoExcepcion, LogicaExcepcion{
        try{
            return valoresRegistrados.cambioEsperado(fecha, definidor,isPrecio);
        } catch (LogicaExcepcion e) {
            throw new LogicaExcepcion(" Posiciones Especies "+e.toString());            
        }
    }
    
    
    
    /**
     *
     * Calcula el valor en riesgo de la posicion dependiendo de la forma como se especifique
     *
     * en el factor de riesgo personal.
     *
     * @param fecha
     *
     * @param numdias
     *
     * @param factor
     *
     * @return
     *
     * @throws LogicaExcepcion Si en caso de utilizar un factor de tipo tasa el contrato no tiene flujos,
     *
     * o si no se puede determinar el valor de la tasa en dicha fecha.
     *
     * @throws DatoInvalidoExcepcion Si la fecha o factor suministrado es nulo, o si
     *
     * en caso de utilizar un factor de tipo tasa el valor de la tasa en esa fecha es menor o igual a -1.
     *
     * Si el factor es de tipo precio y la forma de calculo no permite obtener el valor, si no hay suficientes
     *
     * valores en la serie, si la informacion hallada no alcanza a ser una muestra estadisticamente representativa,
     *
     * o si la serie no permite el calculo utilizando diferencias logaritmicas.
     *
     * @throws FinderException Si en caso de utilizar un factor de tipo tasa no se puede cargar la tasa de descuento.
     *
     */
    
    public double valorEnRiesgo(Date fecha, FactorRiesgoPersonal factor,boolean isPrecio)   throws DatoInvalidoExcepcion, LogicaExcepcion, FinderException{
        if (fecha == null)
            throw new DatoInvalidoExcepcion("La fecha especificada es nula.");
        if (factor==null)
            throw new DatoInvalidoExcepcion("El factor de riesgo suministrado es nulo.");
        
        double var = 0;
        if (factor.getTipo()==FactorRiesgoPersonal.TIPO_FACTORPRECIO){
            double cambioesperado = 0;
            if (factor.getTipoCalculoCambioEsperado()==FactorRiesgoPersonal.CAMBIOESPERADO_FACTORMATRIZ)
                cambioesperado = factor.getFactorRiesgoMatrizCorrelacion().getCambioEsperado();
            else
                cambioesperado = cambioEsperadoValoresRegistrados( fecha, factor.getDefinidorCalculoCambioEsperado(),isPrecio );
            
            var = valorNominal * cambioesperado/100;
            //var = this.saldoContable * cambioesperado;
            
        }else{
            ManejadorFlujos flujosduracion = flujosParaDuracion(fecha);
            Tasa tasa = getTasa(factor.getTasaPK());
            
            double valorDeMercado = flujosduracion.valorDescontado(tasa, fecha);
            double duracion = flujosduracion.duracion(fecha, tasa);
            double tir = flujosduracion.tir();
            double cambioesperado = 0;
            if (factor.getTipoCalculoCambioEsperado()==FactorRiesgoPersonal.CAMBIOESPERADO_FACTORMATRIZ)
                cambioesperado = factor.getFactorRiesgoMatrizCorrelacion().getCambioEsperado();
            else{
                try {   
                    cambioesperado = tasa.cambioEsperadoValoresRegistrados(fecha, factor.getDefinidorCalculoCambioEsperado() );
                } catch (RemoteException e) {
                        
                }
            }
            var = valorDeMercado * duracion / (1+tir) * cambioesperado;
        }
        return var;
    }
    
    
    
    public void eliminarEntidad(){}
    
    
    
    public void actualizarEntidad(){}
    
    
    private double saldoContable=0;

    public double getSaldoContable() {
        return saldoContable;
    }

    public void setSaldoContable(double saldoContable) {
        this.saldoContable = saldoContable;
    }
    
    public void cargarEntidad() throws DatoInvalidoExcepcion, SQLException, Exception{
        ResultSet r1=null;
        try {
            ContratoPK contratoPK = (ContratoPK)ctx.getPrimaryKey();
            long idInterna = contratoPK.getIdInterna();
            conn = getConexion("METRICADB");
            pstmt1 = conn.prepareStatement(
                    "SELECT VALORNOMINAL, P.TIPO AS TIPO, E.ISIN AS ESPECIE, IDESPECIE, " +
                    "M.NOMBRE AS MONEDA, C.SALDOCONTABLE " +
                    "FROM POSICIONESESPECIES P, ESPECIES E, MONEDAS M, CONTRATOS C " +
                    "WHERE P.IDESPECIE=E.ID AND E.IDMONEDA=M.ID AND C.ID=P.ID AND P.ID=? ");
            pstmt1.setLong(1, idInterna );
            r1=pstmt1.executeQuery();
            r1.next();
            
            //Carga de los atributos especificos //valorregistrado
            this.valorNominal = r1.getDouble("VALORNOMINAL");
            
            //carga el saldo contabke 
            this.saldoContable = r1.getDouble("SALDOCONTABLE");
            
            //this.valorCompra = r1.getDouble("VALORCOMPRA");
            setTipo(r1.getString("TIPO"));
            
            this.especiePK = new EspeciePK(r1.getString("ESPECIE"));
            
            //Carga de los atributos generales
            this.monedaPK = new MonedaPK(r1.getString("MONEDA"));
            
            cargarProductoPK(idInterna);
            cargarFlujos(idInterna);
            cargarValoresRegistrados(idInterna, valorNominal);
            cargarTasasDePago(idInterna);
        } catch (SQLException e) {
            e.printStackTrace();
            throw e;
        } catch (DatoInvalidoExcepcion e) {
            e.printStackTrace();
            throw e;
        } catch (NamingException e) {
            e.printStackTrace();
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
            throw new DatoInvalidoExcepcion(e.toString());
        }finally{
            try {conn.close();} catch (Exception e) {}   
            try {pstmt1.close();} catch (Exception e) {}
            try {r1.close();} catch (Exception e) {}
        }
    }
    
    
    
    public ContratoPK ejbFindByPrimaryKey(ContratoPK pk) throws FinderException{
        try{
            conn = getConexion("METRICADB");
            pstmt1 = conn.prepareStatement(
                    "SELECT ID " +                    
                    "FROM POSICIONESESPECIES " +                    
                    "WHERE ID=?");            
            pstmt1.setLong(1, pk.getIdInterna());
            ResultSet r1=pstmt1.executeQuery();            
            if (r1.next()==false)                
                throw new FinderException("No fue posible encontrar la posicion " + pk.toString());            
                        
            return pk;
        }catch(Exception e){            
            throw new EJBException("No fue posible cargar la posicion " + pk.toString() );            
        }finally{            
            try {pstmt1.close();} catch (SQLException e) {}            
            try {conn.close();} catch (SQLException e) {}
        }
    }
    
    
    
    public Collection ejbFindAll() throws FinderException{        
        ArrayList contratos = new ArrayList();        
        ResultSet rs = null;
        try{            
            conn = getConexion("METRICADB");            
            pstmt1 = conn.prepareStatement("SELECT Distinct P.ID from POSICIONESESPECIES P "+                    
                    "INNER JOIN VALORESCONTRATOS V ON P.ID=V.IDCONTRATO "+                    
                    "ORDER BY P.ID");            
                        
            rs = pstmt1.executeQuery();            
            while (rs.next()){                
                contratos.add( new ContratoPK(rs.getLong("ID")));
            }            
        }catch(Exception e){            
            throw new FinderException(e.toString());            
        }finally{            
            try {pstmt1.close();} catch (SQLException e) {}
            try {conn.close();} catch (SQLException e) {}
            try {rs.close();} catch (SQLException e) {}
        }        
        return contratos;        
    }
}